#include "check.h"

#include <stdio.h>
#include <string.h>
#include <memory.h>


CCheck::CCheck(void)
{
    m_bInitialized=false;
    if(!InitIPriv())
	m_bInitialized=true;
}
CCheck::~CCheck(void)
{
    if(m_bInitialized)
	TermIPriv();
}
bool CCheck::operator!(void)
{
    return !m_bInitialized;
}
bool CCheck::operator==(bool n)
{
    if(m_bInitialized==n) return true;
    return false;
}
bool CCheck::LoadPrivateKey(char* buf,pSecretKey key,char* pass)
{
    if(!key) return false;
    memset((char*)key,0,sizeof(SecretKey));
    key->size = sizeof(SecretKey);
    if(!buf || !*buf || !m_bInitialized) return false;
    MemFile* hFile=mfopen((BYTE*)buf,strlen(buf),0);
    MemFile* hFile2=mfopen_w(1024);
    bool res=false;
    if(hFile && hFile2)
    {
	if(!de_docum_mfile(hFile,hFile2,NULL,FALSE,key->userid,&key->keySerial,
	    NULL,NULL))
	{
	    char keystr[MAXKEYLEN+2];
	    byte ideakey[16];
	    strncpy(keystr,pass,MAXKEYLEN+1);
	    hashpass(keystr,strlen(keystr),ideakey);
	    if(!getsecretkey(0,hFile2,key->keySerial,(byte*)&key->timestamp,
		key->userid,ideakey,key->n,key->e,key->d,key->p,key->q,key->u))
	    {
                init_crc();
        	key->crc=CRCINIT;
                key->crc=crcbytes((byte*)key,sizeof(SecretKey),
		    key->crc);
		res=true;
//printf("CountBytes: %i\n",(int)countbytes(key->n)-1);
	    }
	}	    
    }
    if(hFile) mfclose(hFile);
    if(hFile2) mfclose(hFile2);
    if(!res) memset((char*)key,0,sizeof(SecretKey));
    return res;
}
bool CCheck::DoSign(char* message,char* signature,int& size,pSecretKey key)
{
    if(!signature || !size) return false;
    memset(signature,0,size);
    if(!message || !*message || !key) return false;
    bool res=false;
    MemFile* hFile=mfopen((BYTE*)message,strlen(message),0);
    MemFile* hFile2=mfopen_w(1024);
    MemFile* hFile3=mfopen_w(1024);
    if(hFile && hFile2 && hFile3)
    {
        if(checkSecretKey(key))
	{
	    if(!SignMFile(hFile,hFile2,key))
	    {
//		if(!doc_armor_mfile(hFile2,hFile3))
		{
//		    mfseek(hFile3,0,SEEK_END);
//		    mfputc('\0',hFile3);
//		    if(hFile3->m_lpBuffer && hFile3->m_nFileSize)
		    if(hFile2->m_lpBuffer && hFile2->m_nFileSize)
		    {
//			strncpy(signature,(char*)hFile3->m_lpBuffer,size);
			size=(size<hFile2->m_nFileSize)?size:hFile2->m_nFileSize;
			memcpy(signature,(char*)hFile2->m_lpBuffer,size);
			res=true;
		    }
		}
	    }
/*char b[80]="";
GetIPrivLastError(b,80);
printf("%s\n",b);*/
	}
    }
    if(hFile) mfclose(hFile);
    if(hFile2) mfclose(hFile2);
    if(hFile2) mfclose(hFile3);
    if(!res) memset(signature,0,size);
    return res;
}
int CCheck::Sign(char* message,char* key,char* pass,char* out,int size)
{
    if(!out || size<=0) return 0;
    *out=0;
    int res=0;
    SecretKey Key;
    if(!LoadPrivateKey(key,&Key,pass))
	return 0;
    char buf[1024];
    
    int tmp=sizeof(buf);
    if(!DoSign(message,buf,tmp,&Key))
    {
	memset((char*)&Key,0,sizeof(SecretKey));
	return 0;
    }
    MemFile* hFile=mfopen_w(4096);
    MemFile* hFile2=mfopen((BYTE*)message,strlen(message),0);
    MemFile* hFile3=mfopen((BYTE*)buf,tmp,0);
    
    if(hFile && hFile2 && hFile3)
    {
	if(!docum_mfile(hFile2,hFile,hFile3,TRUE,"SM",Key.userid,Key.keySerial,
	    NULL,0))
	{
	    mfseek(hFile,0,SEEK_END);
	    mfputc('\0',hFile);
	    if(hFile->m_lpBuffer && hFile->m_nFileSize)
	    {
	    	strncpy(out,(char*)hFile->m_lpBuffer,size);
		res=strlen(out);
	    }
	}
    }
    if(hFile) mfclose(hFile);
    if(hFile2) mfclose(hFile2);
    if(hFile3) mfclose(hFile3);
    memset((char*)&Key,0,sizeof(SecretKey));
    return res;
}
bool CCheck::LoadPublicKey(char* buf,pPublicKey key)
{
    if(!key) return false;
    memset((char*)key,0,sizeof(PublicKey));
    key->size = sizeof(PublicKey);
    if(!buf || !*buf || !m_bInitialized) return false;

    MemFile* hFile=mfopen((BYTE*)buf,strlen(buf),0);
    MemFile* hFile2=mfopen_w(1024);
    bool res=false;
    long fp;
    int pktlen;
    if(hFile && hFile2)
    {
	if(!de_docum_mfile(hFile,hFile2,NULL,FALSE,key->userid,&key->keySerial,
	    NULL,NULL))
	{
//printf("OK\n%i\n",hFile2->m_nFileSize);
	    if(!getpublickey(0,hFile2,key->keySerial, &fp, &pktlen,
		(byte*)&key->timestamp,key->userid,key->n,key->e))
	    {
                init_crc();
        	key->crc=CRCINIT;
                key->crc=crcbytes((byte*)key,sizeof(PublicKey),
		    key->crc);
		res=true;
//printf("CountBytes: %i\n",(int)countbytes(key->n)-1);
	    }
	}	    
    }
    if(hFile) mfclose(hFile);
    if(hFile2) mfclose(hFile2);
    if(!res) memset((char*)key,0,sizeof(PublicKey));
    return res;
}



bool CCheck::DoCheckSign(char* message,int ms,char* signature,int ss,pPublicKey key)
{
    if(!message || !*message || !signature || !*signature || !key)
	return false;
    bool res=false;
    MemFile* hFile=mfopen((BYTE*)message,ms,0);
//    MemFile* hFile=mfopen((BYTE*)message,strlen(message),0);
    MemFile* hFile2=mfopen((BYTE*)signature,ss,0);
    if(hFile && hFile2)
    {
	if(checkPublicKey(key))
	{
	    if(!CheckMFileSign(hFile,hFile2,key))
		res=true;
	}
    }
    if(hFile) mfclose(hFile);
    if(hFile2) mfclose(hFile2);
    return res;
}


bool CCheck::CheckSign(char* message,char* key,char* out,int size)
{
    if(out) *out=0;
    if(!key || !message || !*message) return false;
    PublicKey Key;
    if(!LoadPublicKey(key,&Key))
	return false;

    MemFile* hFile=mfopen((BYTE*)message,strlen(message),0);
    MemFile* hFile2=mfopen_w(4096);
    MemFile* hFile3=mfopen_w(1024);
    bool res=false;
    
    if(hFile && hFile2 && hFile3)
    {
	char userid[256];
	long keySerial;
	if(!de_docum_mfile(hFile,hFile2,hFile3,TRUE,userid,&keySerial,NULL,NULL))
	{
	    mfseek(hFile2,0,SEEK_END);
	    mfputc('\0',hFile2);

	    if(keySerial==Key.keySerial)
	    {
		res=DoCheckSign((char*)hFile2->m_lpBuffer,hFile2->m_nFileSize-1,
		    (char*)hFile3->m_lpBuffer,hFile3->m_nFileSize,&Key);
		if(res && out && size>0)
		{
		    strncpy(out,(char*)hFile2->m_lpBuffer,size);
		}
	    }
	}
    }
    if(hFile) mfclose(hFile);
    if(hFile2) mfclose(hFile2);
    if(hFile3) mfclose(hFile3);
    return res;
}
